#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>

#include "libfdt.h"

#define DTB_FILE_NAME "demo.dtb"

unsigned long get_file_size(const char *path)  
{  
    unsigned long filesize = -1;      
    struct stat statbuff;  
    if(stat(path, &statbuff) < 0){  
        return filesize;  
    }else{  
        filesize = statbuff.st_size;  
    }  
    return filesize;  
}  


int main()
{
	int ret = 0;
	int dtb_size = -1;
	char* dtb_buf = NULL; 
	int fd = open(DTB_FILE_NAME, O_RDONLY);
	if (fd < 0)
	{
		printf("open %s failed!!!\n", DTB_FILE_NAME);
		return -1;
	}

	dtb_size = get_file_size(DTB_FILE_NAME);
	if (dtb_size < 0)
	{
		printf("dtb size %d not good!!!\n", dtb_size);
		goto EXIT;
	}
	printf("dtb file: %s  size:%d\n", DTB_FILE_NAME, dtb_size);

	dtb_buf = malloc(dtb_size);
	if (NULL == dtb_buf)
	{
		printf("malloc dtb buf (%d)failed!!!\n", dtb_size);
		goto EXIT;
	}
	memset(dtb_buf, 0, dtb_size);

	ret = read(fd, dtb_buf, dtb_size);
	if (ret != dtb_size)
	{
		printf("read dtb failed (%d)!!!\n", ret);
		goto EXIT;
	}
	ret = fdt_check_header(dtb_buf);
	if (ret != 0)
	{
		printf("check dtb header failed (%d)!!!\n", ret);
		goto EXIT;
	}
	else
	{
		printf("check dtb header success!!!\n");
	}
	int nodeoffset = fdt_path_offset(dtb_buf, "/memory/cma");
	if (nodeoffset < 0)
	{
		printf("failed to offset for /memory/cma = %d \n", nodeoffset);
		goto EXIT;
	}

	int len;
	const void *nodep = fdt_getprop(dtb_buf, nodeoffset, "reg", &len);
	if (len == 0 || nodep == NULL)
	{
		printf("failed to access /memory/cma reg.\n");
		goto EXIT;
	}

	unsigned int *p_data = (unsigned int *)nodep;
	printf("DDR0: start: %#x, len:%#x DDR1: start: %#x, len:%#x\n", 
			ntohl(p_data[0]), ntohl(p_data[1]), ntohl(p_data[2]), ntohl(p_data[3]));

	unsigned int val[4] = {0};
	val[0] =htonl(0x600000);
	val[1] = htonl(0x100000);
	val[2] = htonl(0x800000);
	val[3] = htonl(0x200000);

	ret = fdt_setprop(dtb_buf, nodeoffset, "reg", val, 16);
	if (ret != 0)
	{
		printf("set reg failed!!!\n");
		goto EXIT;
	}

	nodep = fdt_getprop(dtb_buf, nodeoffset, "reg", &len);
	if (len == 0 || nodep == NULL)
	{
		printf("failed to access /memory/cma reg.\n");
		goto EXIT;
	}

	p_data = (unsigned int *)nodep;
	printf("AFFTER DDR0: start: %#x, len:%#x DDR1: start: %#x, len:%#x\n", 
			ntohl(p_data[0]), ntohl(p_data[1]), ntohl(p_data[2]), ntohl(p_data[3]));

	
EXIT:
	if (!dtb_buf)
	{
		free(dtb_buf);
	}
	if (fd >= 0)
	{
		close(fd);
	}
	return 0;
}
